// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UIRefreshThread.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.UI.Forms
{
    #region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Threading;

    #endregion

    /// <summary>
    /// The ui refresh thread.
    /// </summary>
    public class UIRefreshThread : IDisposable
    {
        #region Constants and Fields

        /// <summary>
        /// The MsTime.
        /// </summary>
        private const int MsTime = 200;

        /// <summary>
        /// The refreshables.
        /// </summary>
        private readonly List<UIRefreshable> refreshables = new List<UIRefreshable>();

        /// <summary>
        /// The refreshablesLocker.
        /// </summary>
        private readonly Locker refreshablesLocker = new Locker();

        /// <summary>
        /// The thread.
        /// </summary>
        private readonly Thread thread;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UIRefreshThread"/> class.
        /// </summary>
        public UIRefreshThread()
        {
            this.thread = new Thread(this.ThreadLoop);
            this.thread.Name = "UIRefreshThread (UI Refresh)";
            this.thread.IsBackground = true;
            this.thread.Priority = ThreadPriority.AboveNormal;
            this.thread.Start();
        }

        #endregion

        #region Delegates

        /// <summary>
        /// The invoke delegate.
        /// </summary>
        public delegate void InvokeDelegate();

        #endregion

        #region Public Methods

        /// <summary>
        /// The add refreshable.
        /// </summary>
        /// <param name="refreshable">
        /// The refreshable.
        /// </param>
        public void AddRefreshable(UIRefreshable refreshable)
        {
            using (this.refreshablesLocker.Lock())
            {
                if (!this.refreshables.Contains(refreshable))
                {
                    this.refreshables.Add(refreshable);
                }
            }
        }

        /// <summary>
        /// The remove refreshable.
        /// </summary>
        /// <param name="refreshable">
        /// The refreshable.
        /// </param>
        public void RemoveRefreshable(UIRefreshable refreshable)
        {
            using (this.refreshablesLocker.Lock())
            {
                if (this.refreshables.Contains(refreshable))
                {
                    this.refreshables.Remove(refreshable);
                }
            }
        }

        /// <summary>
        /// The terminate.
        /// </summary>
        public void Terminate()
        {
            Devel.NoThrow(() => this.thread.Abort());
        }

        #endregion

        #region Implemented Interfaces

        #region IDisposable

        /// <summary>
        /// The dispose.
        /// </summary>
        public void Dispose()
        {
        }

        #endregion

        #endregion

        #region Methods

        /// <summary>
        /// The thread loop.
        /// </summary>
        private void ThreadLoop()
        {
            // For ever
            while (true)
            {
                try
                {
                    // Keep track of start time
                    var start = Timings.Now;

                    // Refresh the whole refreshable list at once
                    try
                    {
                        using (this.refreshablesLocker.Lock())
                        {
                            foreach (var refreshable in this.refreshables)
                            {
                                var info = refreshable.RefreshInfo;
                                using (info.Locker.Lock())
                                {
                                    try
                                    {
                                        var now = Timings.Now;

                                        if (now - info.RefreshedOn > info.RefreshPeriod && info.RefreshNeeded)
                                        {
                                            // Is refreshed now
                                            info.RefreshedOn = now;
                                            info.RefreshNeeded = false;

                                            // Invoke the appropriate repaint (the implementation must use the form.BeginInvoke() 
                                            // on its own control to avoid cross-thread access)
                                            try
                                            {
                                                info.UIRefresh();
                                            }
                                            catch (Exception)
                                            {
                                            }
                                        }
                                    }
                                    catch (Exception)
                                    {
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }

                    // Keep track of end
                    var end = Timings.Now;

                    // Sleep some time if refreshing didn't take too long
                    var elapsed = end - start;
                    if (elapsed.TotalMilliseconds < MsTime)
                    {
                        var sleeptime = MsTime - (int)elapsed.TotalMilliseconds;
                        Devel.NoThrow(delegate { Thread.Sleep(sleeptime); });
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        #endregion

        // #region UIRefreshThread Members

        // public UIForm CreateForm(string title, EUIFormLayoutType layout, EUIFormClosingType closing, UIControl hostedControl)
        // {
        // //Stdout.WriteLine("Form \"" + title + "\" was created from thread " + System.Threading.Thread.CurrentThread.GetHashCode());
        // UIForm form = new UIForm(title, layout, closing, hostedControl);
        // return form;
        // }

        // #endregion
    }
}